package org.dromara.oce.config;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.UUID;

/**
 * @desc: 模拟发送client请求
 * @author: hhl
 * @date：2025/8/7 14:55
 */
public class NettyClient {
    public static final String host = "172.17.13.163";
    public static final int port = 8082;


    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap()
                .group(group)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 添加字节数组编解码器
                        ch.pipeline().addLast(new ByteArrayEncoder());
                        ch.pipeline().addLast(new ByteArrayDecoder());
                        // 添加客户端处理器来处理接收的消息
                        ch.pipeline().addLast(new ClientMessageHandler());
//                        ch.pipeline().addLast(new DeviceSessionHandler(new DeviceServiceImpl()));
                    }
                });

            // 连接到服务器
            ChannelFuture future = bootstrap.connect(host, port).sync();
            System.out.println("Connected to server at " + host + ":" + port);

            // 发送心跳帧
            future.channel().writeAndFlush(buildHeartbeat("SN123456"));
//            future.channel().writeAndFlush(Unpooled.wrappedBuffer(buildHeartbeat("SN123456789ABC")));

//            future.channel().writeAndFlush(sendDeviceBasicParam());

//            future.channel().writeAndFlush(buildRealtimeDataUploadMessage());

//            future.channel().writeAndFlush(buildRequestTestParamMessage());

            future.channel().writeAndFlush(buildTestParamUploadMessage());

//            future.channel().writeAndFlush(buildTestParamModifyMessage());

//            future.channel().writeAndFlush(buildAlarmEventMessage());

//            future.channel().writeAndFlush(buildStartTestEventMessage());

//            future.channel().writeAndFlush(buildRemoteControlMessage(0,1));

//            testFileUpload(future);

            // 等待一段时间以接收服务器回应
//            Thread.sleep(10000);

            // 等待连接关闭
//            future.channel().closeFuture().sync();
        } finally {
//            group.shutdownGracefully();
        }
    }


    /**
     * 构造心跳帧(0x01)
     *
     * @param sn 设备序列号
     * @return 心跳帧字节数组
     */
    private byte[] buildHeartbeat(String sn) {
        byte[] snBytes = sn.getBytes(Charset.forName("ASCII"));

        // payload结构: SN长度(1) + SN内容 + 时间戳(4)
        int frameLength = 1 + 1 + snBytes.length + 4;
        ByteBuffer payloadBuffer = ByteBuffer.allocate(frameLength);
        payloadBuffer.order(ByteOrder.BIG_ENDIAN);
        // SN长度
        payloadBuffer.put((byte) snBytes.length);
        // SN内容
        payloadBuffer.put(snBytes);
        // 当前时间戳 (Unix时间戳，秒级)
        int currentTimestamp = (int) (System.currentTimeMillis() / 1000);
        payloadBuffer.putInt(currentTimestamp);
        System.out.println("构建心跳帧payload参数: SN长度=" + snBytes.length + "，SN=" + sn + ", 时间戳=" + currentTimestamp);
        return DeviceUtil.buildDataFrame(MessageType.HEARTBEAT, payloadBuffer.array());
    }

    /**
     * 发送设备基础参数上报（0x04）
     */
    public byte[] sendDeviceBasicParam() {
        // SN长度（假设SN为"123456"）
        String sn = "SN123456";
        byte snLength = (byte) sn.length();
        // 设备基础参数JSON字符串
        String jsonStr = "{\"deviceName\":\"FCDB-A1026SG\",\"deviceType\":5,\"deviceVersion\":\"1.0.1123\",\"protocolVersion\":\"Tcp 2.0\",\"equaliserChannelConfig\":\"1-24\"}";
        byte[] jsonBytes = jsonStr.getBytes(StandardCharsets.UTF_8);

        // 计算消息总长度: SN长度(1) + SN内容 + JSON数据
        int totalLength = 1 + 1 + snLength + jsonBytes.length;

        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        buffer.order(ByteOrder.BIG_ENDIAN);

        // SN长度
        buffer.writeByte(snLength);
        // SN内容
        buffer.writeBytes(sn.getBytes(StandardCharsets.US_ASCII));
        // 设备基础参数JSON字符串
        buffer.writeBytes(jsonBytes);
        return DeviceUtil.buildDataFrame(MessageType.DEVICE_BASIC_PARAM_UPLOAD, buffer.array());
    }

    /**
     * 设备实时数据上报（0x06）
     *
     * @return ByteBuf格式的消息
     */
    private static void buildRealtimeDataUploadMessage(ChannelHandlerContext ctx, byte[] byteBuf) {
        // SN信息
        String sn = "SN123456";
        byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
        byte snLength = (byte) snBytes.length;

        // 实时数据JSON数组
        String jsonStr = "[{\"channelIndex\":0,\"testDataUUID\":\"e21cd4cb-d63b-4d5f-8681-2ab8ed2178bd\",\"workModel\":1,\"testType\":1,\"testStatus\":1,\"stepNo\":\"1/2\",\"groupValueList\":[{\"title\":\"组端电压\",\"value\":\"51.221\",\"unit\":\"V\",\"type\":1,\"sort\":1},{\"title\":\"组端电流\",\"value\":\"21.5\",\"unit\":\"A\",\"type\":2,\"sort\":2}],\"batteryList\":[{\"groupCode\":\"\",\"batteryCode\":1,\"valueList\":[{\"title\":\"电压\",\"value\":\"3.235\",\"unit\":\"V\",\"type\":1,\"sort\":0}]},{\"groupCode\":\"\",\"batteryCode\":2,\"valueList\":[{\"title\":\"电压\",\"value\":\"3.212\",\"unit\":\"V\",\"type\":1,\"sort\":0}]}]}]";

        byte[] jsonBytes = jsonStr.getBytes(StandardCharsets.UTF_8);
        // 计算消息总长度: SN长度(1) + SN内容 + JSON数据
        int totalLength = 1 + 1 + snLength + jsonBytes.length;
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入SN长度
        buffer.writeByte(snLength);
        // 写入SN内容
        buffer.writeBytes(snBytes);
        // 写入JSON数据
        buffer.writeBytes(jsonBytes);
        byte[] bytes = DeviceUtil.buildDataFrame(MessageType.REALTIME_DATA_UPLOAD, buffer.array());
        ctx.writeAndFlush(Unpooled.copiedBuffer(bytes));
    }

    /**
     * 5.7获取当前测试参数（0x07）
     *
     * @return ByteBuf格式的消息
     */
    private static byte[] buildRequestTestParamMessage() {
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(1);
        // 写入通道号，默认为0
        buffer.writeByte((byte) 1);
        return DeviceUtil.buildDataFrame(MessageType.REQUEST_TEST_PARAM, buffer.array());
    }

    /**
     * 5.8测试参数上报（0x08）
     *
     * @return ByteBuf格式的消息
     */
    public byte[] buildTestParamUploadMessage() {
        // SN信息
        String sn = "SN123456";
        byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
        byte snLength = (byte) snBytes.length;

        // 测试参数JSON数据
        String jsonStr = "{\"channelIndex\":0,\"paramGroupList\":[{\"groupName\":\"基本参数\",\"sort\":0,\"paramList\":[{\"title\":\"电池类型\",\"value\":\"磷酸铁锂\",\"unit\":\"\",\"editable\":false,\"sort\":1,\"range\":\"[三元锂,磷酸铁锂]\",\"fileType\":\"select\"},{\"title\":\"电芯数量\",\"value\":\"24\",\"unit\":\"\",\"editable\":false,\"sort\":2,\"range\":\"[1,24]\",\"fileType\":\"int\"}]},{\"groupName\":\"充电参数\",\"sort\":1,\"paramList\":[{\"title\":\"充电电压\",\"value\":\"107.1\",\"unit\":\"V\",\"editable\":true,\"sort\":1,\"range\":\"[2,300]\",\"fileType\":\"double\"},{\"title\":\"充电电流\",\"value\":\"50\",\"unit\":\"A\",\"editable\":true,\"sort\":2,\"range\":\"(0,50]\",\"fileType\":\"double\"}]}]}";
        byte[] jsonBytes = jsonStr.getBytes(StandardCharsets.UTF_8);

        // 计算消息总长度: SN长度(1) + SN内容 + JSON数据
        int totalLength = 1 + 1 + snLength + jsonBytes.length;

        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入SN长度
        buffer.writeByte(snLength);
        // 写入SN内容
        buffer.writeBytes(snBytes);
        // 写入JSON数据
        buffer.writeBytes(jsonBytes);
        return DeviceUtil.buildDataFrame(MessageType.TEST_PARAM_UPLOAD, buffer.array());
    }


    /**
     * 5.9测试参数修改（0x09）
     *
     * @return ByteBuf格式的消息
     */
    private static byte[] buildTestParamModifyMessage() {
        // 请求标识（8字节）
        byte[] requestId = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

        // 测试参数修改JSON数据
        String jsonStr = "{\n" +
            "  \"channelIndex\": 0,\n" +
            "  \"paramGroupList\": [\n" +
            "    {\n" +
            "      \"groupName\": \"基本参数\",\n" +
            "      \"paramList\": [\n" +
            "        {\n" +
            "          \"title\": \"电池类型\",\n" +
            "          \"value\": \"磷酸铁锂\"\n" +
            "        },\n" +
            "        {\n" +
            "          \"title\": \"电芯数量\",\n" +
            "          \"value\": \"24\"\n" +
            "        }\n" +
            "      ]\n" +
            "    },\n" +
            "    {\n" +
            "      \"groupName\": \"充电参数\",\n" +
            "      \"paramList\": [\n" +
            "        {\n" +
            "          \"title\": \"充电电压\",\n" +
            "          \"value\": \"107.1\"\n" +
            "        },\n" +
            "        {\n" +
            "          \"title\": \"充电电流\",\n" +
            "          \"value\": \"50\"\n" +
            "        }\n" +
            "      ]\n" +
            "    }\n" +
            "  ]\n" +
            "}";

        byte[] jsonBytes = jsonStr.getBytes(StandardCharsets.UTF_8);
        // 计算消息总长度: 请求标识(8) + JSON数据
        int totalLength = 1 + 8 + jsonBytes.length;
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入消息类型 (0x09)
        buffer.writeByte(MessageType.TEST_PARAM_MODIFY);
        // 写入请求标识
        buffer.writeBytes(requestId);
        // 写入JSON数据
        buffer.writeBytes(jsonBytes);
        return buffer.array();
    }


    /**
     * 5.11设备事件上报（0x0B）
     * 构造设备事件上报消息（0x0B）
     *
     * @param eventType    事件类型 (1:启动测试, 2:停止测试, 3:测试过程中参数修改, 4:告警)
     * @param eventContent 事件内容JSON字符串
     * @return byte[]格式的消息
     */
    private static byte[] buildDeviceEventReportMessage(int eventType, String eventContent) {
        // SN信息
        String sn = "SN123456";
        byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
        byte snLength = (byte) snBytes.length;

        // 事件时间（Unix时间戳）
        int eventTimestamp = (int) (System.currentTimeMillis() / 1000);

        // 事件内容JSON数据
        byte[] eventContentBytes = eventContent.getBytes(StandardCharsets.UTF_8);

        // 计算消息总长度: SN长度(1) + SN内容 + 事件类型(1) + 事件时间(4) + 事件内容
        int totalLength = 1 + 1 + snLength + 1 + 4 + eventContentBytes.length;

        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);

        // 写入消息类型 (0x0B)
        buffer.writeByte(MessageType.DEVICE_EVENT_REPORT);

        // 写入SN长度
        buffer.writeByte(snLength);

        // 写入SN内容
        buffer.writeBytes(snBytes);

        // 写入事件类型
        buffer.writeByte((byte) eventType);

        // 写入事件时间
        buffer.writeInt(eventTimestamp);

        // 写入事件内容
        buffer.writeBytes(eventContentBytes);

        return buffer.array();
    }

    /**
     * 构造启动测试事件消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildStartTestEventMessage() {
        String eventContent = "{\n" +
            "  \"realTimeData\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"testDataUUID\": \"" + UUID.randomUUID().toString() + "\",\n" +
            "    \"workModel\": 1,\n" +
            "    \"testType\": 1,\n" +
            "    \"testStatus\": 1,\n" +
            "    \"stepNo\": \"1/2\"\n" +
            "  },\n" +
            "  \"testConfig\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"paramGroupList\": [\n" +
            "      {\n" +
            "        \"groupName\": \"充电参数\",\n" +
            "        \"paramList\": [\n" +
            "          {\n" +
            "            \"title\": \"充电电压\",\n" +
            "            \"value\": \"107.1\"\n" +
            "          }\n" +
            "        ]\n" +
            "      }\n" +
            "    ]\n" +
            "  }\n" +
            "}";

        return buildDeviceEventReportMessage(1, eventContent);
    }

    /**
     * 构造停止测试事件消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildStopTestEventMessage() {
        String eventContent = "{\n" +
            "  \"realTimeData\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"testDataUUID\": \"" + UUID.randomUUID().toString() + "\",\n" +
            "    \"workModel\": 1,\n" +
            "    \"testType\": 1,\n" +
            "    \"testStatus\": 0,\n" +
            "    \"stepNo\": \"2/2\"\n" +
            "  },\n" +
            "  \"stopReason\": \"测试时间到\"\n" +
            "}";

        return buildDeviceEventReportMessage(2, eventContent);
    }

    /**
     * 构造测试过程中参数修改事件消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildParamModifiedDuringTestEventMessage() {
        String eventContent = "{\n" +
            "  \"oldTestConfig\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"paramGroupList\": [\n" +
            "      {\n" +
            "        \"groupName\": \"充电参数\",\n" +
            "        \"paramList\": [\n" +
            "          {\n" +
            "            \"title\": \"充电电压\",\n" +
            "            \"value\": \"100.0\"\n" +
            "          }\n" +
            "        ]\n" +
            "      }\n" +
            "    ]\n" +
            "  },\n" +
            "  \"newTestConfig\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"paramGroupList\": [\n" +
            "      {\n" +
            "        \"groupName\": \"充电参数\",\n" +
            "        \"paramList\": [\n" +
            "          {\n" +
            "            \"title\": \"充电电压\",\n" +
            "            \"value\": \"107.1\"\n" +
            "          }\n" +
            "        ]\n" +
            "      }\n" +
            "    ]\n" +
            "  }\n" +
            "}";

        return buildDeviceEventReportMessage(3, eventContent);
    }

    /**
     * 构造告警事件消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildAlarmEventMessage() {
        String eventContent = "{\n" +
            "  \"realTimeData\": {\n" +
            "    \"channelIndex\": 0,\n" +
            "    \"testDataUUID\": \"" + UUID.randomUUID().toString() + "\",\n" +
            "    \"workModel\": 1,\n" +
            "    \"testType\": 1,\n" +
            "    \"testStatus\": 1,\n" +
            "    \"stepNo\": \"1/2\"\n" +
            "  },\n" +
            "  \"alarmMsg\": \"单体模块1#脱落\"\n" +
            "}";

        return buildDeviceEventReportMessage(4, eventContent);
    }

    /**
     * 5.12工作模式切换（0x0C）
     *
     * @param channelIndex 通道号
     * @param workMode     工作模式 (1:充电, 2:放电, 3:均衡, 4:活化/工步)
     * @return byte[]格式的消息
     */
    private static byte[] buildWorkModeSwitchMessage(int channelIndex, int workMode) {
        // 请求标识（8字节）
        byte[] requestId = new byte[]{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18};
        // 计算消息总长度: 请求标识(8) + 通道号(1) + 工作模式(1)
        int totalLength = 1 + 8 + 1 + 1;
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入消息类型 (0x0C)
        buffer.writeByte(MessageType.WORK_MODE_SWITCH);
        // 写入请求标识
        buffer.writeBytes(requestId);
        // 写入通道号
        buffer.writeByte((byte) channelIndex);
        // 写入工作模式
        buffer.writeByte((byte) workMode);
        return buffer.array();
    }


    /**
     * 构造充电模式切换消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildChargeModeSwitchMessage() {
        return buildWorkModeSwitchMessage(0, 1); // 通道号0，充电模式
    }

    /**
     * 构造放电模式切换消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildDischargeModeSwitchMessage() {
        return buildWorkModeSwitchMessage(0, 2); // 通道号0，放电模式
    }

    /**
     * 构造均衡模式切换消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildBalanceModeSwitchMessage() {
        return buildWorkModeSwitchMessage(0, 3); // 通道号0，均衡模式
    }

    /**
     * 构造活化/工步模式切换消息
     *
     * @return byte[]格式的消息
     */
    public static byte[] buildActivationModeSwitchMessage() {
        return buildWorkModeSwitchMessage(0, 4); // 通道号0，活化/工步模式
    }


    /**
     * 5.14远程控制切换（0x0E）
     *
     * @param channelIndex 通道号
     * @param controlType  控制类型 (1:启动测试, 2:停止测试, 3:暂停测试, 4:继续测试)
     * @return byte[]格式的消息
     */
    private static byte[] buildRemoteControlMessage(int channelIndex, int controlType) {
        // 请求标识（8字节）
        byte[] requestId = new byte[]{0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28};

        // 计算消息总长度: 请求标识(8) + 通道号(1) + 控制类型(1)
        int totalLength = 1 + 8 + 1 + 1;
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入消息类型 (0x0E)
        buffer.writeByte(MessageType.REMOTE_CONTROL);
        // 写入请求标识
        buffer.writeBytes(requestId);
        // 写入通道号
        buffer.writeByte((byte) channelIndex);
        // 写入控制类型
        buffer.writeByte((byte) controlType);
        return buffer.array();
    }


    public void testFileUpload(ChannelFuture future) throws InterruptedException {
        // 生成测试记录唯一标识（16字节）
        byte[] testRecordId = generateTestRecordId();

        // 模拟要上传的文件数据
        String fileContent = "这是一段测试文件内容，用于模拟设备上传的测试数据。" +
            "文件内容可以包含任何测试相关的信息，比如测试结果、日志等。" +
            "为了测试分包传输，我们将创建一个较长的文件内容。" +
            "这部分内容将被分割成多个数据包进行传输。" +
            "每个包的数据长度不能超过255字节。" +
            "设备需要按照顺序发送所有数据包。" +
            "平台收到每个包后需要发送ACK确认。" +
            "如果设备没有收到ACK确认，需要重新发送该数据包。" +
            "最多重传3次，如果仍然失败则上传失败。";

        byte[] fileData = fileContent.getBytes(StandardCharsets.UTF_8);

        // 分包传输，每包不超过255字节
        int packetSize = 200; // 每包200字节
        int totalPackets = (int) Math.ceil((double) fileData.length / packetSize);

        System.out.println("文件总大小: " + fileData.length + " 字节");
        System.out.println("总包数: " + totalPackets);

        // 逐个发送数据包
        for (int i = 0; i < totalPackets; i++) {
            // 计算当前包的数据
            int start = i * packetSize;
            int end = Math.min((i + 1) * packetSize, fileData.length);
            int length = end - start;

            byte[] packetData = new byte[length];
            // 将文件数据从指定起始位置复制到数据包缓冲区中
            // 从fileData数组的start位置开始，复制length个字节到packetData数组的0位置开始
            System.arraycopy(fileData, start, packetData, 0, length);


            // 构造测试文件上传消息
            byte[] message = buildTestFileUploadMessage(testRecordId, totalPackets, i + 1, packetData);

            // 发送消息
            future.channel().writeAndFlush(Unpooled.copiedBuffer(message)).sync();

            System.out.println("已发送第 " + (i + 1) + " 个文件包，大小: " + length + " 字节");

            // 等待一段时间以确保消息被处理
            Thread.sleep(1000);
        }
        System.out.println("测试文件上传完成");
    }


    /**
     * 构造测试文件上传消息（0x10）
     *
     * @param testRecordId        测试记录唯一标识（16字节）
     * @param totalPackets        总包数
     * @param currentPacketNumber 当前包序号
     * @param packetData          包数据（不超过255字节）
     * @return byte[]格式的消息
     */
    private static byte[] buildTestFileUploadMessage(byte[] testRecordId, int totalPackets, int currentPacketNumber, byte[] packetData) {
        // SN信息
        String sn = "SN123456";
        byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
        byte snLength = (byte) snBytes.length;

        // 包数据长度（不能超过255字节）
        if (packetData.length > 255) {
            throw new IllegalArgumentException("包数据长度不能超过255字节");
        }
        byte packetDataLength = (byte) packetData.length;
        // 计算消息总长度: SN长度(1) + SN内容 + 测试记录唯一标识(16) + 总包数(2) + 当前包序号(2) + 包数据长度(1) + 包数据
        int totalLength = 1 + 1 + snLength + 16 + 2 + 2 + 1 + packetData.length;
        // 创建ByteBuf
        ByteBuf buffer = Unpooled.buffer(totalLength);
        // 写入消息类型 (0x10)
        buffer.writeByte(MessageType.TEST_FILE_UPLOAD);
        // 写入SN长度
        buffer.writeByte(snLength);
        // 写入SN内容
        buffer.writeBytes(snBytes);
        // 写入测试记录唯一标识
        buffer.writeBytes(testRecordId);
        // 写入总包数
        buffer.writeShort((short) totalPackets);
        // 写入当前包序号
        buffer.writeShort((short) currentPacketNumber);
        // 写入包数据长度
        buffer.writeByte(packetDataLength);
        // 写入包数据
        buffer.writeBytes(packetData);
        return buffer.array();
    }

    /**
     * 生成测试记录唯一标识（16字节）
     *
     * @return 16字节的测试记录ID
     */
    private static byte[] generateTestRecordId() {
        // 使用UUID生成唯一标识，然后取前16字节
        UUID uuid = UUID.randomUUID();
        long mostSigBits = uuid.getMostSignificantBits();
        long leastSigBits = uuid.getLeastSignificantBits();
        byte[] testRecordId = new byte[16];

        // 填充前8字节
        for (int i = 0; i < 8; i++) {
            testRecordId[i] = (byte) (mostSigBits >> (8 * (7 - i)));
        }
        // 填充后8字节
        for (int i = 0; i < 8; i++) {
            testRecordId[8 + i] = (byte) (leastSigBits >> (8 * (7 - i)));
        }
        return testRecordId;
    }


    /**
     * 客户端消息处理器 - 处理从服务器接收到的消息
     */
    private static class ClientMessageHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("=== 接收到服务器消息 ===");
            ByteBuf byteBuf = null;
            // 处理设备发送的数据
            // 类型检查和转换
            if (msg instanceof ByteBuf) {
                byteBuf = (ByteBuf) msg;
                // 安全地读取缓冲区内容用于打印
                byte[] bytes = new byte[byteBuf.readableBytes()];
                byteBuf.getBytes(byteBuf.readerIndex(), bytes);
                System.out.println("接收《服务端》原始数据: " + DeviceUtil.bytesToHex(bytes));
            } else if (msg instanceof byte[]) {
                // 如果是字节数组，包装为ByteBuf
                byte[] bytes = (byte[]) msg;
                System.out.println("接收《服务端》原始数据: " + DeviceUtil.bytesToHex(bytes));
                byteBuf = Unpooled.wrappedBuffer(bytes);
            } else {
                System.out.println("《客户端》不支持的消息类型: " + msg.getClass().getName());
                return;
            }

            byte messageType = DeviceUtil.getMessageType(byteBuf);
            System.out.println("消息类型: 0x" + String.format("%02X", messageType));
            byte[] payload = DeviceUtil.getPayload(byteBuf);

            switch (messageType) {
                case MessageType.HEARTBEAT_RESPONSE: // 心跳回应
                    handleHeartbeatResponse(payload);
                    break;
                case MessageType.REQUEST_REALTIME_DATA:
                    buildRealtimeDataUploadMessage(ctx, payload);
                    break;
                case MessageType.TEST_PARAM_MODIFY:
                    this.handleTestParamModify(ctx, payload);
                    break;
                case MessageType.WORK_MODE_SWITCH:
                    this.handleWorkModeSwitch(ctx, payload);
                    break;
                case MessageType.REMOTE_CONTROL:
                    this.handleRemoteControl(ctx, payload);
                    break;


                case MessageType.TEST_FILE_UPLOAD_RESPONSE://测试文件上传回应
                    handleTestFileUploadResponse(payload);
                    break;
                default:
                    System.out.println("未知消息类型: 0x" + String.format("%02X", messageType));
                    break;
            }
        }

        /**
         * 处理心跳回应消息
         *
         * @param payload 心跳回应数据
         */
        private void handleHeartbeatResponse(byte[] payload) {
            if (payload.length < 4) { // 最小长度: 时间戳(4)
                System.out.println("心跳回应数据长度不足");
                return;
            }

            // 直接解析时间戳（前4个字节）
            ByteBuffer buffer = ByteBuffer.wrap(payload, 0, 4);
            buffer.order(ByteOrder.BIG_ENDIAN);
            int timestamp = buffer.getInt();
            System.out.println("  时间戳: " + timestamp);
        }


        /**
         * 5.9测试参数修改（0x09）
         *
         * @param ctx
         * @param byteBuf
         */
        public void handleTestParamModify(ChannelHandlerContext ctx, byte[] byteBuf) {
            // 读取请求标识（8字节）
            byte[] requestId = DeviceUtil.getContentByte(byteBuf, 0, 8);

            // 读取回应内容
            byte[] requestContentBytes = DeviceUtil.getContentByte(byteBuf, 8, byteBuf.length - 8);
            String requestContent = new String(requestContentBytes, Charset.forName("UTF-8"));

            System.out.println("收到测试参数修改回应:");
            System.out.println("  请求标识: " + DeviceUtil.bytesToLong(requestId));
            System.out.println("  修改内容: " + requestContent);

            if (1==1) {
                System.out.println("测试参数修改成功");
                byte[] bytes = buildTestParamModifyResponse("SN123456", requestId, 200, "修改成功");
                ctx.writeAndFlush(Unpooled.copiedBuffer(bytes));
            } else {
                byte[] bytes = buildTestParamModifyResponse("SN123456", requestId, 400, "修改失败");
                ctx.writeAndFlush(Unpooled.copiedBuffer(bytes));
                System.out.println("测试参数修改失败");
            }
        }


        /**
         * 5.10测试参数修改回应（0x0A）
         *
         * @param ctx
         * @param byteBuf
         * @return
         */
        public byte[] buildTestParamModifyResponse(String sn, byte[] requestId, int responseCode, String responseContent) {
            byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
            byte snLength = (byte) snBytes.length;

            byte[] responseContentBytes = responseContent.getBytes(StandardCharsets.UTF_8);
            short responseContentLength = (short) responseContentBytes.length;

            // 计算总长度: SN长度(1) + SN内容 + 请求标识(8) + 回应码(1) + 回应内容长度(2) + 回应内容
            int totalLength = 1 + snLength + 8 + 1 + 2 + responseContentBytes.length;
            ByteBuffer buffer = ByteBuffer.allocate(totalLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            // 写入SN长度
            buffer.put(snLength);
            // 写入SN内容
            buffer.put(snBytes);
            // 写入请求标识（8字节）
            buffer.put(requestId);
            // 写入回应码
            buffer.put((byte)responseCode);
            // 写入回应内容长度
            buffer.putShort(responseContentLength);
            // 写入回应内容
            buffer.put(responseContentBytes);
            return DeviceUtil.buildDataFrame(MessageType.TEST_PARAM_MODIFY_RESPONSE, buffer.array());

        }


        public void handleWorkModeSwitch(ChannelHandlerContext ctx, byte[] byteBuf) {
            try {
                // 读取请求标识（8字节）
                byte[] requestId = DeviceUtil.getContentByte(byteBuf, 0, 8);

                // 读取通道号（1字节）
                byte channelIndex = byteBuf[8];

                // 读取工作模式（1字节）
                byte workMode = byteBuf[8+1];

                System.out.println("收到工作模式切换请求:");
                System.out.println("  请求标识: " + DeviceUtil.bytesToHex(requestId));
                System.out.println("  通道号: " + (channelIndex & 0xFF));
//                System.out.println("  工作模式: " + (workMode & 0xFF) + " (" + WorkModeEnum.fromCode(workMode & 0xFF) + ")");

                // TODO: 验证设备是否处于未测试状态
                // TODO: 执行工作模式切换操作
                // TODO: 发送工作模式切换回应（0x0D）消息给平台

                if (workMode == 1 ) {
                    System.out.println("切换到工作模式: " + 1);
                    // 可以在这里添加实际的工作模式切换逻辑
                    // 发送工作模式切换成功回应（0x0D）
                    ctx.writeAndFlush(Unpooled.copiedBuffer(buildWorkModeSwitchResponseMessage(requestId, 200, "工作模式切换成功")));
                } else {
                    System.out.println("无效的工作模式: " + (workMode & 0xFF));
                }

            } catch (Exception e) {
                System.out.println("处理工作模式切换失败: " + e.getMessage());
                e.printStackTrace();
            }
        }

        public byte[] buildWorkModeSwitchResponseMessage(byte[] requestId, int responseCode, String responseContentStr) {
            // SN信息
            String sn = "SN123456";
            byte[] snBytes = sn.getBytes(StandardCharsets.US_ASCII);
            byte snLength = (byte) snBytes.length;

            // 回应内容
            byte[] responseContentBytes = responseContentStr.getBytes(StandardCharsets.UTF_8);

            // 回应内容长度（2字节）
            short responseContentLength = (short) responseContentBytes.length;

            // 计算消息总长度: SN长度(1) + SN内容 + 请求标识(8) + 回应码(1) + 回应内容长度(2) + 回应内容
            int totalLength = 1 + snLength + 8 + 1 + 2 + responseContentBytes.length;

            ByteBuffer buffer = ByteBuffer.allocate(totalLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            // 写入SN长度
            buffer.put(snLength);
            // 写入SN内容
            buffer.put(snBytes);
            // 写入请求标识（8字节）
            buffer.put(requestId);
            // 写入回应码
            buffer.put((byte)responseCode);
            // 写入回应内容长度
            buffer.putShort(responseContentLength);
            // 写入回应内容
            buffer.put(responseContentBytes);
            return DeviceUtil.buildDataFrame(MessageType.WORK_MODE_SWITCH_RESPONSE, buffer.array());
        }


        public void handleRemoteControl(ChannelHandlerContext ctx, byte[] byteBuf) {
            try {
                // 读取请求标识（8字节）
                byte[] requestId = DeviceUtil.getContentByte(byteBuf, 0, 8);
                // 读取通道号（1字节）
                byte channelIndex = byteBuf[8];
                // 读取控制类型（1字节）
                byte controlType = byteBuf[8 + 1];

                System.out.println("收到远程控制请求:");
                System.out.println("  请求标识: " + DeviceUtil.bytesToHex(requestId));
                System.out.println("  通道号: " + (channelIndex & 0xFF));
                System.out.println("  控制类型: " + (controlType & 0xFF));

                // TODO: 执行远程控制操作
                if (controlType == 1) {
                    System.out.println("执行远程控制操作: " + controlType);
                    // 可以在这里添加实际的远程控制逻辑

                    // 发送远程控制成功回应（0x0F）
                    byte[] response = DeviceUtil.buildDataFrame(MessageType.REMOTE_CONTROL_RESPONSE, buildRemoteControlResponseMessage(requestId, controlType, 200, "远程控制操作成功"));
                    ctx.writeAndFlush(Unpooled.copiedBuffer(response));
                } else {
                    System.out.println("无效的控制类型: " + (controlType & 0xFF));
                    // 发送远程控制失败回应（0x0F）
                    byte[] response = DeviceUtil.buildDataFrame(MessageType.REMOTE_CONTROL_RESPONSE, buildRemoteControlResponseMessage(requestId, null, 400, "无效的控制类型"));
                    ctx.writeAndFlush(Unpooled.copiedBuffer(response));
                }

            } catch (Exception e) {
                System.out.println("处理远程控制失败: " + e.getMessage());
                e.printStackTrace();

                // 发送远程控制错误回应（0x0F）
                byte[] response = DeviceUtil.buildDataFrame(MessageType.REMOTE_CONTROL_RESPONSE, buildRemoteControlResponseMessage(new byte[8], null, 500, "处理远程控制时发生错误: " + e.getMessage()));
                ctx.writeAndFlush(Unpooled.copiedBuffer(response));
            }
        }

        public byte[] buildRemoteControlResponseMessage(byte[] requestId, Byte controlType, int responseCode, String responseContent) {
            // SN信息（这里使用固定SN，实际应用中应从上下文中获取）
            String sn = "SN123456";
            byte[] snBytes = sn.getBytes(Charset.forName("ASCII"));
            byte snLength = (byte) snBytes.length;

            // 回应内容
            byte[] responseContentBytes = responseContent.getBytes(Charset.forName("UTF-8"));

            // 回应内容长度（2字节）
            short responseContentLength = (short) responseContentBytes.length;

            // 计算消息总长度: SN长度(1) + SN内容 + 请求标识(8) + 回应码(1) + 回应内容长度(2) + 回应内容
            int totalLength = 1 + 1 + snLength + 8 + 1 + 2 + responseContentBytes.length;

            // 创建ByteBuffer
            ByteBuffer buffer = ByteBuffer.allocate(totalLength);
            buffer.order(ByteOrder.BIG_ENDIAN);
            // 写入SN长度
            buffer.put(snLength);
            // 写入SN内容
            buffer.put(snBytes);
            // 写入请求标识
            buffer.put(requestId);
            // 写入回应码
            buffer.put((byte)responseCode);
            // 写入回应内容长度
            buffer.putShort(responseContentLength);
            // 写入回应内容
            buffer.put(responseContentBytes);
            return buffer.array();
        }



        /**
         * 模拟测试文件上传回应内容解析
         *
         * @param payload
         */
        public void handleTestFileUploadResponse(byte[] payload) {
            try {
                if (payload.length < 23) { // 最小长度: 类型(1) + 测试记录唯一标识(16) + 当前包序号(2) + 回应码(1) + 回应内容长度(2)
                    System.out.println("测试文件上传回应数据长度不足");
                    return;
                }

                // 读取测试记录唯一标识（16字节）
                byte[] testRecordId = new byte[16];
                System.arraycopy(payload, 1, testRecordId, 0, 16);

                // 读取当前包序号（2字节）
                short currentPacketNumber = (short) (((payload[17] & 0xFF) << 8) | (payload[18] & 0xFF));

                // 读取回应码（1字节）
                byte responseCode = payload[19];

                // 读取回应内容长度（2字节）
                short responseContentLength = (short) (((payload[20] & 0xFF) << 8) | (payload[21] & 0xFF));

                // 读取回应内容
                String responseContent = "";
                if (responseContentLength > 0 && payload.length >= 22 + responseContentLength) {
                    byte[] responseContentBytes = new byte[responseContentLength];
                    System.arraycopy(payload, 22, responseContentBytes, 0, responseContentLength);
                    responseContent = new String(responseContentBytes, StandardCharsets.UTF_8);
                }

                System.out.println("收到测试文件上传回应:");
                System.out.println("  测试记录唯一标识: " + DeviceUtil.bytesToHex(testRecordId));
                System.out.println("  当前包序号: " + (currentPacketNumber & 0xFFFF));
                System.out.println("  回应码: " + (responseCode & 0xFF));
                System.out.println("  回应内容: " + responseContent);

                // TODO: 根据回应码处理回应结果
                if (responseCode == (byte) 200) {
                    System.out.println("测试文件包上传成功");
                    // 可以在这里更新文件传输状态或发送下一个包
                } else {
                    System.out.println("测试文件包上传失败");
                }

            } catch (Exception e) {
                System.out.println("处理测试文件上传回应失败: " + e.getMessage());
                e.printStackTrace();
            }
        }


        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            System.out.println("客户端发生异常:");
            cause.printStackTrace();
            ctx.close();
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("与服务器的连接已建立");
            super.channelActive(ctx);
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            System.out.println("与服务器的连接已断开");
            super.channelInactive(ctx);
        }
    }


    public static void main(String[] args) throws Exception {
        new NettyClient().start();
    }
}
